#include "TestLua.hpp"
#include "SLB.hpp"
#include <map>
using namespace SLB;
#include "ScriptComponent.hpp"


template<class Key, class Value>
struct  MapWrapper : public std::map<Key, Value>
{
	MapWrapper() {
		static int customIndex = 0;
		index = customIndex++;
	}
	Value get(Key k)
	{
		SLB_DEBUG_CALL;
		SLB_DEBUG(2, "map::GET [%s->%s]", _TIW(Key).name(), _TIW(Value).name())
			return (*this)[k];
	}
	void set(Key k, Value v)
	{
		SLB_DEBUG_CALL;
		SLB_DEBUG(2, "map::SET [%s->%s]", _TIW(Key).name(), _TIW(Value).name())
			(*this)[k] = v; 
	}

	int index;
};

typedef MapWrapper<const char *, int> MapStringInt;
typedef MapWrapper<int, const char *> MapIntString;
typedef MapWrapper<const char *, const char *> MapStringString;

/*
class CustomComponent : public MapStringString {
public:
	CustomComponent() {
		static int customIndex = 0;
		index = customIndex++;
	}

	int index;
private:
	
};
*/
/*
class ScriptComponent {

public:
	ScriptComponent() {
		static int ScriptComponentIndex = 0;
		index = ScriptComponentIndex++;
	}

	~ScriptComponent(){

	}


	const char* get(const char* key)
	{
		SLB_DEBUG_CALL;
		SLB_DEBUG(2, "map::GET [%s->%s]", _TIW(Key).name(), _TIW(Value).name())
			return map[key];
	}
	void set(const char* k, const char* v)
	{
		SLB_DEBUG_CALL;
		SLB_DEBUG(2, "map::SET [%s->%s]", _TIW(Key).name(), _TIW(Value).name())
			map[k] = v; 
	}

	int index;

private:
	typedef map<const char*, const char*> Map;
	Map map;
};
*/

static int componentCounter = 0;

Component::Component() {
	this->type = componentCounter++;
}

Component::Component(const Component& other) {
	type = other.type;
}

Component::~Component() {

}


	


class Drawable : public Component {
public:
	Drawable() {
		Mesh = 100;
	}
	
	~Drawable() {}

	int Mesh;

};

static Drawable drawable;


class GObject {
public:

	

	GObject() {
		static int counter =  0;
		index = counter++;
	}

	~GObject() {

	}

	CustomComponent* AddComponent(CustomComponent* comp) {
		CustomComponent* copy = new CustomComponent(*comp);
		components[comp->index] = copy;
		return copy;
	}

	CustomComponent* GetComponent(CustomComponent* comp) {
		Components::iterator it = components.find(comp->index);
		if (it!=components.end()) {
			return components[comp->index];
		} else {
			return 0;
		}
	}

	void SetTable(std::string info) {

		string s = info;

	}


private:
	int index;
	typedef std::map<int, CustomComponent*> Components;
	Components components;

};


class LinkPoint {
public:
	LinkPoint() {
		x = 0;
		y = 0;
		string s = "Vector constructor";
		OutputDebugStringA(s.c_str());
	}

	~LinkPoint() {
		string s = "Vector destructor";
		OutputDebugStringA(s.c_str());
	}

	float x,y;

	float Length() {
		return sqrtf(x*x+y*y);
	}
	

};


class MainLoop : public SLB::Script {
public:
	MainLoop(SLB::Manager* m) : SLB::Script(m) {


	}

	void Update(float dt) {
		lua_State *L = getState();
		// prepare a call object
		SLB::LuaCall<void(float)> call(L,"Update");
		// perform the call with the parameters
		call(dt);
	}


};

static int destroySprite(lua_State* L)
{
	
	return 0;
}

int class__index(lua_State *L)
{
	SLB_DEBUG_CALL;
	SLB_DEBUG(2, "Test __index metamethod & getCache");
	SLB::ClassInfo *c = SLB::Manager::defaultManager()->getClass(L,1);
	if (c)
	{
		c->getCache(L);
	}
	else
	{
		luaL_error(L, "Invalid class at #1");
	}
	return 1;
}


int class__newindex(lua_State *L)
{
	SLB_DEBUG_CALL;
	SLB_DEBUG(2, "Test __newindex metamethod & setCache");
	SLB::ClassInfo *c = SLB::Manager::defaultManager()->getClass(L,1);
	

	

	if (c)
	{
		c->setCache(L);
	}
	else
	{
		luaL_error(L, "Invalid class at #1");
	}
	return 0;
}

void TestLua::Initialize()
{

	//SLB::Manager m;

	/*
	SLB::Class<MapStringString>("Map")
		.constructor()
		.object__index( &MapStringString::get )
		.object__newindex( &MapStringString::set )
		;
		*/
	
	ScriptComponent::InitScripting();

	SLB::Class< LinkPoint > ("LinkPoint")
		.constructor()
		.property("x", &LinkPoint::x)
		.property("y", &LinkPoint::y)
		.set("Length", &LinkPoint::Length)
		;

	SLB::Class< GObject > ("GameObject")
		.constructor()
		.set("AddComponent", &GObject::AddComponent)
		.set("GetComponent", &GObject::GetComponent)
		.set("SetTable", &GObject::SetTable)
		;

	SLB::Class< Component > ("Component")
		.constructor()
		.class__index(&class__index)
		.class__newindex(&class__newindex)
		.object__index(&class__index)
		.object__newindex(&class__newindex)
		;

	SLB::Class< Drawable > ("Drawable")
		.constructor()
		.dynamic_inherits<Component>()
		.property("mesh", &Drawable::Mesh)
		;
	
	MainLoop s(SLB::Manager::defaultManager());

	
	
	try
	{
		s.doFile("d:/testLUA4.lua");
	}
	catch (std::runtime_error e)
	{
		std::string error = e.what();
	}

	for (int i=0; i<10; i++)
	{
		s.Update(0.5f);
	}

	

}

void TestLua::Update(float dt) {


}

void TestLua::Render() {


}